//! Some basic and fragmented components

/* from stdlib */
use crate::alloc::vec::Vec;

#[repr(u8)]
pub enum CVoid {
    __Variant1,
    __Variant2,
}

#[derive(Debug)]
pub enum RTTError {
    ThreadStartupErr,
    MutexTakeTimeout,
    SemaphoreTakeTimeout,
    QueueSendTimeout,
    QueueReceiveTimeout,
    OutOfMemory,

    DeviceNotFound,
    DeviceOpenFailed,
    DeviceCloseFailed,
    DeviceReadFailed,
    DeviceWriteFailed,
    DeviceConfigFailed,
    DeviceSetRxCallBackFailed,
    DeviceSetTxCallBackFailed,

    FuncUnDefine,
}

static mut PRINT_LOCK:*const CVoid = 0 as *const CVoid;

pub(crate) struct CString {
    pub str: Vec<u8>
}

impl CString {
    pub(crate) fn new(str:&str) -> Self {
        let mut temp: Vec<u8> =
            str.as_bytes().iter().cloned().collect();
        temp.push(0);
        CString {
            str: temp,
        }
    }
}

pub type RTBaseError = isize;
pub type CCharPtr= *const u8;
pub type CVoidPtr= *const CVoid;

/* from rtthread */
extern {

    // typedef struct rt_mutex *rt_mutex_t;
    // rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag)
    // create mutex
    // flag: RT_IPC_FLAG_FIFO: 0
    //       RT_IPC_FLAG_PRIO: 1
    fn rt_mutex_create(name: *const u8, flag: u8) -> *const CVoid;

    // typedef long        rt_base_t;
    // typedef rt_base_t   rt_err_t;       /**< Type for error number */
    // rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t time)
    fn rt_mutex_take(handle: *const CVoid, tick: i32) -> isize;

    // rt_err_t rt_mutex_release(rt_mutex_t mutex)
    fn rt_mutex_release(handle: *const CVoid) -> isize;

    // rt_err_t rt_mutex_delete(rt_mutex_t mutex)
    fn rt_mutex_delete(handle: *const CVoid) -> isize;

    // typedef rt_uint32_t  rt_tick_t; /**< Type for tick count */
    // rt_err_t rt_thread_delay(rt_tick_t tick)
    fn rt_thread_delay(tick: u32) -> isize;

    // rt_err_t rt_thread_mdelay(rt_int32_t ms)
    fn rt_thread_mdelay(tick: i32) -> isize;

    // void rt_kputs(const char *str)
    fn rt_kputs(s: *const u8);

    // typedef unsigned long rt_ubase_t;  /**< Nbit unsigned CPU related data type */
    // typedef rt_ubase_t   rt_size_t;  /**< Type for size number */
    // void *rt_malloc(rt_size_t size)
    fn rt_malloc(size: usize) -> *mut u8;

    // void rt_free(void *rmem)
    fn rt_free(ptr: *mut u8);

    // rt_thread_t rt_thread_create(const char *name,
    // void (*entry)(void *parameter),
    // void       *parameter,
    // rt_uint32_t stack_size,
    // rt_uint8_t  priority,
    // rt_uint32_t tick)
    fn rt_thread_create(name: *const u8,
                        func: extern "C" fn(p:*mut CVoid),
                        param: *mut CVoid,
                        stack_size: u32,
                        priority: u8,
                        tick: u32) -> *const CVoid;

    // rt_err_t rt_thread_delete(rt_thread_t thread)
    fn rt_thread_delete(handle: *const CVoid) -> isize;

    // rt_err_t rt_thread_startup(rt_thread_t thread)
    fn rt_thread_startup(th: *const CVoid) -> isize;

    // rt_err_t rt_thread_yield(void)
    fn rt_thread_yield() -> isize;


    // rt_mq_t rt_mq_create(const char *name,
    // rt_size_t   msg_size,
    // rt_size_t   max_msgs,
    // rt_uint8_t  flag)
    fn rt_mq_create(name: *const u8, message_size: usize,
                    len: usize, flag:u8)-> *const CVoid;

    // rt_err_t rt_mq_send_wait(rt_mq_t     mq,
    // const void *buffer,
    // rt_size_t   size,
    // rt_int32_t  timeout)
    fn rt_mq_send_wait(handle: *const CVoid, msg: *const CVoid,
                       msg_size: usize, tick: i32) -> isize;

    // rt_err_t rt_mq_recv(rt_mq_t    mq,
    // void      *buffer,
    // rt_size_t  size,
    // rt_int32_t timeout)
    fn rt_mq_recv(handle: *const CVoid, msg: *mut CVoid,
                       msg_size: usize, tick: i32) -> isize;

    // rt_err_t rt_mq_delete(rt_mq_t mq)
    fn rt_mq_delete(handle: *const CVoid) -> isize;
}

pub fn rttbase_init() {
    let name = CString::new("prt");
    unsafe {
        PRINT_LOCK = rt_mutex_create(name.str.as_ptr(), 1);
    }
}

#[inline]
pub(crate) fn rttbase_thread_delay(tick: u32)
{
    unsafe {
        rt_thread_delay(tick);
    }
}

#[inline]
pub(crate) fn rttbase_thread_mdelay(tick: i32)
{
    unsafe {
        rt_thread_mdelay(tick);
    }
}

#[inline]
pub(crate) fn rttbase_print_lock()
{
    unsafe {
        rt_mutex_take(PRINT_LOCK, -1);
    }
}

#[inline]
pub(crate) fn rttbase_print_unlock()
{
    unsafe {
        rt_mutex_release(PRINT_LOCK);
    }
}

#[inline]
pub(crate) fn rttbase_print(str: &str)
{
    let s = CString::new(str);
    unsafe {
        rt_kputs(s.str.as_ptr());
    }
}

#[inline]
pub(crate) fn rttbase_malloc(size: usize) -> *mut u8{
    unsafe {
        rt_malloc(size)
    }
}

#[inline]
pub(crate) fn rttbase_free(ptr: *mut u8) {
    unsafe {
        rt_free(ptr);
    }
}

#[inline]
pub(crate) fn rttbase_thread_create(name: &str,
                                    func: extern "C" fn(p:*mut CVoid),
                                    param: *mut CVoid,
                                    stack_size: u32,
                                    priority: u8,
                                    tick: u32) -> *const CVoid
{
    let s = CString::new(name);
    unsafe {
        rt_thread_create(s.str.as_ptr(), func, param,
                         stack_size, priority, tick)
    }
}

pub(crate) fn rttbase_thread_delete(handle: *const CVoid)
{
    unsafe {
        rt_thread_delete(handle);
    }
}

#[inline]
pub(crate) fn rttbase_thread_startup(th: *const CVoid) -> isize {
    unsafe {
        rt_thread_startup(th)
    }
}

#[inline]
pub(crate) fn rttbase_thread_yield()
{
    unsafe {
        rt_thread_yield();
    }
}

#[inline]
pub(crate) fn rttbase_mutex_create() -> *const CVoid
{
    let s = CString::new("rust");
    unsafe {
        rt_mutex_create(s.str.as_ptr(), 1)
    }
}

#[inline]
pub(crate) fn rttbase_mutex_delete(handle: *const CVoid)
{
    unsafe {
        rt_mutex_delete(handle);
    }
}

#[inline]
pub(crate) fn rttbase_mutex_take(handle: *const CVoid, tick:i32) -> isize
{
    unsafe {
        rt_mutex_take(handle,tick)
    }
}

#[inline]
pub(crate) fn rttbase_mutex_release(handle: *const CVoid)
{
    unsafe {
        rt_mutex_release(handle);
    }
}

#[inline]
pub(crate) fn rttbase_queue_create(len: usize, message_size:usize) -> *const CVoid
{
    let s = CString::new("rust");
    unsafe {
        rt_mq_create(s.str.as_ptr(),
                     message_size, len, 0)
    }
}

#[inline]
pub(crate) fn rttbase_queue_send_wait(handle: *const CVoid, msg: *const CVoid,
                                      msg_size: usize, tick: i32) -> isize
{
    unsafe {
        rt_mq_send_wait(handle, msg, msg_size, tick)
    }
}

#[inline]
pub(crate) fn rttbase_queue_receive(handle: *const CVoid, msg: *mut CVoid,
                                      msg_size: usize, tick: i32) -> isize
{
    unsafe {
        rt_mq_recv(handle, msg, msg_size, tick)
    }
}

#[inline]
pub(crate) fn rttbase_queue_delete(handle: *const CVoid)
{
    unsafe {
        rt_mq_delete(handle);
    }
}